package cn.mrcode.wxsdk.core.dialogue.common.accessToken.lifeCycle.single;


import cn.mrcode.wxsdk.core.dialogue.common.LogUtil;
import cn.mrcode.wxsdk.core.dialogue.common.accessToken.AccessTokenApi;
import cn.mrcode.wxsdk.core.dialogue.common.exception.ReqException;
import cn.mrcode.wxsdk.core.dialogue.common.exception.WxException;
import cn.mrcode.wxsdk.core.dialogue.common.util.DateUtil;
import cn.mrcode.wxsdk.core.dialogue.protocol.base.AccessTokenInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.DelayQueue;

/**
 * @author zhuqiang
 * @version V1.0
 * @Description: accessToken维护 单机版
 * @date 2015/9/8 9:03
 */
public class AccessTokenSingleTask implements Runnable{
    private static Logger log = LoggerFactory.getLogger(AccessTokenSingleTask.class);
    private ConcurrentHashMap<String, AccessTokenInfo> map;
    private DelayQueue<AccessTokenInfo> queue;
    private boolean timeOutDestroy = false;  //超时功能是否打开标志
    private int time; //超时时间

    public AccessTokenSingleTask(DelayQueue<AccessTokenInfo> queue, ConcurrentHashMap<String, AccessTokenInfo> map) {
        this.queue = queue;
        this.map = map;
    }

    /**
     * 打开 超时指定时间不使用accessToken则销毁该token的缓存对象
     * @param flag 超时功能 标志
     * @param time 超时时间，单位为 分钟
     */
    public void openTimeOutDestroy(boolean flag,int time){
        this.timeOutDestroy = flag;
        this.time = time;
    }
    @Override
    public void run() {
        while (true) {
            try {
                AccessTokenInfo ati = queue.take();  //获取超时的 对象
                String appID = ati.getAppID();
                if (timeOutDestroy) {  //超过了设定的未使用时间，则把token对象移除
                    Date overtime = DateUtil.computingTime(ati.getLastUseTime(), Calendar.MINUTE, time);
                    if (overtime.getTime() < new Date().getTime()) { //已经超时了
                        map.remove(appID);
                        log.info(ati.getAppID() + "该微信公众号的accessToken已经被移除了（由于太久未被使用）");
                        continue;
                    }
                }

                try {
                    ati = AccessTokenApi.getAccessTokenInfo(appID, ati.getAppSecret());
                } catch (ReqException e) {
                    log.error(LogUtil.fromateLog(e));
                } catch (WxException e) {
                    log.error(LogUtil.fromateLog(e));
                }
                map.put(appID,ati);
                queue.add(ati);
                log.info(appID + "该微信公众号的accessToken已经更新了（由于已经快超时了）");
            } catch (InterruptedException e) {
                log.error("AccessTokenTask 任务被中断:" + e.getMessage());
                e.printStackTrace();
            }
        }
    }
}
